import {
  TableInterface,
  headerParseResult,
  BodyParseResult,
  HeaderConfig,
  ColumnItem
} from './typedefs'
abstract class TableParseInterface {
  public columnsParseResult: headerParseResult | null = null
  public bodyParseResult: BodyParseResult | [] = []
  public defaultHeaderConfig: HeaderConfig
  public canvas: HTMLCanvasElement
  public ctx: CanvasRenderingContext2D | null
  constructor() {
    this.canvas = document.createElement('canvas')
    this.ctx = this.canvas.getContext('2d') as CanvasRenderingContext2D
    this.defaultHeaderConfig = {
      cellText: {
        fontSize: 12,
        fontColor: '#D76860',
        fontFamily: 'PingFang SC',
        fontWeight: 'normal',
        textBaseline: 'middle',
        textAlign: 'center',
        lineHeight: 1.5
      },
      cell: {
        minWidth: 55,
        minHeight: 32,
        fillColor: '#FFFAF5',
        borderWidth: 1,
        borderColor: '#FDDAD1',
        padding: [10, 10]
      },
      border: true,
      fit: true
    }
  }

  /**
   * 抽象方法，用于解析表格配置并绘制表格
   * @param {Object} table - 表格配置对象
   * @returns {Promise<void>} - 解析完成后的异步操作（在子类中实现具体逻辑）
   */
  abstract parseTable(table: TableInterface): Promise<void>
  // 钩子函数
  // 表格解析开始前钩子函数类型
  onBeforeParse?: (table: TableInterface) => void
  // 定义表头解析前钩子函数类型
  onBeforeParseHeader?(columns: ColumnItem[]): void

  // 定义表头解析钩子函数类型
  onParseHeaderCol?(col: any, colIndex: number): void
  // 表头解析每列处理后钩子函数类型，返回处理后的列配置
  //  onAfterParseHeaderCol?(col: ColumnConfig, colIndex: number, headerParseResult: any): ColumnConfig;
  // 表头解析完成后钩子函数类型
  onAfterParseHeader?: (headerParseResult: headerParseResult) => void
  // 表格体解析开始前钩子函数类型
  onBeforeParseBody?(data: any[]): void
  // 表格体解析每行处理前钩子函数类型
  onBeforeParseBodyRow?(row: any, rowIndex: number): void
  // 表格体解析每行每列处理后钩子函数类型
  onAfterParseBodyCell?(
    cellValue: any,
    rowIndex: number,
    colIndex: number,
    dataParseResult: any
  ): void
  // 表格体解析完成后钩子函数类型
  onAfterParseBody?: (dataParseResult: BodyParseResult) => void
  // 表格解析完成后钩子函数类型
  onAfterParse?: (parseResult: { header: headerParseResult; data: BodyParseResult }) => void

  // 具体方法
  /**
   * 将字符串按照指定长度进行分割，并返回分割后的字符串数组。
   *
   * @param label 需要分割的字符串
   * @param splitNum 每个分割后字符串的长度
   * @returns 分割后的字符串数组
   */
  splitLabel(label: string, splitNum: number): string[] {
    if (splitNum === 0) return label.split('<br/>')
    const content: string[] = []
    for (let index = 0; index < label.length; index += splitNum) {
      content.push(label.substring(index, splitNum + index))
    }
    return content
  }

  /**
   * 根据对齐方式返回相应的文本对齐方式。
   *
   * @param align 对齐方式，可选值为 'left'（左对齐）、'center'（居中对齐）、'right'（右对齐）或空字符串。
   * @returns 返回相应的文本对齐方式，'left'（左对齐）、'center'（居中对齐）、'right'（右对齐）或 'start'（起始对齐）。
   */
  getTextAlignFromAlignment(
    align: 'left' | 'center' | 'right' | ''
  ): 'left' | 'center' | 'right' | 'start' {
    switch (align) {
      case 'center':
        return 'center'
      case 'left':
        return 'right'
      case 'right':
        return 'left'
      default:
        return 'start'
    }
  }

  /**
   * 根据给定的参数计算单元格的位置
   *
   * @param index 单元格的索引
   * @param start 起始位置
   * @param widthList 宽度列表
   * @param height 高度
   * @param level 层级
   * @param isHeader 是否为表头
   * @returns 返回单元格的位置，包括 x 和 y 坐标
   */
  handleCellLocation(
    index: number,
    start: number,
    widthList: number[],
    height: number,
    level: number,
    isHeader: boolean
  ): { x: number; y: number } {
    const x = widthList.reduce((acc, width, i) => (i < index ? acc + width : acc), start)
    const y = isHeader ? level * height : start + (height - start) * (index === 0 ? 0 : 1)
    return { x, y }
  }

  // 计算单元格的宽度
  // 如果没有设置宽度，则计算单元格的宽度
  // 根据设置的字体大小和字体family利用canvas进行测量
  // 还需考虑单元格内容换行的情况
  calculateCellWidth(
    ctx: CanvasRenderingContext2D,
    content: string,
    minWidth: number,
    wordBreak: number = 0,
    fontSize: number = 12,
    fontFamily: string = 'PingFang SC',
    padding: number[] | number = 10
  ): number {
    let width = 0
    ctx.font = `${fontSize}px ${fontFamily}`
    width = Math.max(
      this.splitLabel(content, wordBreak).reduce(
        (maxWidth, text) => Math.max(ctx.measureText(text).width, maxWidth),
        0
      ),
      1
    )
    if (Array.isArray(padding)) {
      width += padding[1] + padding[3]
    } else {
      width += padding * 2
    }
    return Math.max(width, minWidth)
  }

  calculateCellHeight(
    content: string,
    minHeight: number = 0,
    fontSize: number = 12,
    wordBreak: number = 0,
    padding: number[] | number = 10,
    lineHeight: number = 1.5
  ): number {
    let height = 0
    const baseLineHeight = fontSize * lineHeight
    height += this.splitLabel(content, wordBreak).length * baseLineHeight
    if (Array.isArray(padding)) {
      height += padding[0] + padding[2]
    } else {
      height += padding * 2
    }
    return Math.max(height, minHeight)
  }
}

export default TableParseInterface
